package com.fulihui.usercore.core.processor.auth;

import com.fulihui.usercore.common.util.AppProps;
import com.fulihui.usercore.common.util.Errors;
import com.fulihui.usercore.core.repository.WechatOpenidHelpRepository;
import com.fulihui.usercore.core.repository.WechatUserRepository;
import com.fulihui.usercore.dto.UserDTO;
import com.fulihui.usercore.dto.WechatUserDTO;
import com.fulihui.usercore.enums.*;
import com.fulihui.usercore.request.auth.AbstractAuthRequest;
import com.fulihui.usercore.request.auth.WechatAuthRequest;
import com.fulihui.usercore.sdk.domain.SignTypeEnum;
import org.near.servicesupport.error.CommonServiceErrorEnum;
import org.near.servicesupport.error.InvokeServiceException;
import org.near.toolkit.common.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;

/**
 * 微信注册基于快捷登陆，注册后直接通过openid查询关联用户
 * @author Willard.Hu on 2016/11/9 0009.
 */
@Component("wechatLoginAuthProcessor")
public class WechatLoginAuthProcessor extends AbstractAuthProcessor {

    @Autowired
    private WechatUserRepository wechatUserRepository;
    @Autowired
    private WechatOpenidHelpRepository wechatOpenidHelpRepository;
    @Autowired
    private AppProps             appProps;

    /**
     * Openid 查询关联用户，查到返回 userid 否则返回 null
     */
    @Override
    public String login(AbstractAuthRequest request) {
        WechatAuthRequest wechatAuthRequest = (WechatAuthRequest) request;
        String defaultAppid;
        if (WechatOpenIdTypeEnum.WECHAT_MP.getCode().equals(wechatAuthRequest.getOpenidType())) {
            defaultAppid = appProps.getWechatMpAppid();
        } else if (WechatOpenIdTypeEnum.NATIVE_APP.getCode().equals(
                wechatAuthRequest.getOpenidType())) {
            defaultAppid = appProps.getWechatAppAppid();
        } else {
            throw new InvokeServiceException(CommonServiceErrorEnum.REQUEST_PARAMETER_ERROR);
        }
        // 向下兼容处理，如果appid为空，使用默认微信公众号标识
        if (StringUtil.isBlank(wechatAuthRequest.getAppid())) {
            wechatAuthRequest.setAppid(defaultAppid);
        }
        WechatUserDTO wechatUserDTO = wechatOpenidHelpRepository.querySingle(wechatAuthRequest.getOpenid(),
                wechatAuthRequest.getOpenidType(), defaultAppid);

        if (wechatUserDTO == null) {
            return null;
        }
        // XXX 对只预注册的处理，以前预注册只会落地微信，用户不会存，将这种微信信息置为无效，之后用户可以重新注册
        UserDTO userDTO = userRepository.queryByPK(wechatUserDTO.getUserId());
        if (userDTO == null) {
            boolean b = wechatUserRepository.updateDsiable(1, wechatUserDTO.getUserId());
            if (!b) {
                throw new InvokeServiceException(CommonServiceErrorEnum.SYSTEM_ERROR);
            }
            return null;
        }
        //fixme 客户关系不再维护
        //bindingCustomer(userDTO.getMobileNo(), userDTO.getUserId());
        String userId = wechatUserDTO.getUserId();
        checkLoginUserState(userId);
        signPublish(request, userId, SignTypeEnum.SIGN_IN);
        asyncSignInExecute(userId, request);
        return userId;

    }

    @Override
    public String authType() {
        return UserRegisterTypeEnum.WECHAT.getCode();
    }

    @Override
    protected UserDTO toUserModel(AbstractAuthRequest request) {
        WechatAuthRequest wechatAuthRequest = (WechatAuthRequest) request;
        UserDTO userDTO = new UserDTO();
        userDTO.setRegisterType(authType());
        userDTO.setRegisterSource(request.getRegisterSource());
        if (wechatAuthRequest.getSex() == 1) {
            userDTO.setGender(UserGenderEnum.MEN.getCode());
        } else if (wechatAuthRequest.getSex() == 2) {
            userDTO.setGender(UserGenderEnum.WOMEN.getCode());
        } else {
            userDTO.setGender(UserGenderEnum.UNKNOW.getCode());
        }
        if (StringUtil.isNotBlank(wechatAuthRequest.getNickname())) {
            userDTO.setNickname(StringUtil.filterEmoji(wechatAuthRequest.getNickname()));
        } else {
            userDTO.setNickname(nicknameGenerator.generate());
        }

        // XXX 目前微信登入用的是快捷登入功能，快捷登陆账号就是手机号
        userDTO.setMobileNo(request.getLoginId());
        userDTO.setMobileVerified(BooleanValueEnum.TRUE.isTrue());

        userDTO.setHeadImg(wechatAuthRequest.getHeadImg());
        userDTO.setState(UserStateEnum.NOMAL.getCode());
        userDTO.setRoleCode("USER_NOMAL");
        userDTO.setProvince(request.getProvince());
        userDTO.setCity(request.getCity());
        Date now = new Date();
        userDTO.gmtCreate(now);
        userDTO.lastLogin(now);
        userDTO.setErduoVersion(request.getErduoVersion());

        if (request.getUsedProduct() != null) {
            userDTO.setUsedProducts(singletonList(request.getUsedProduct()));
        }

        Map<String, Object> param = new HashMap<>();
        if (StringUtil.isNotBlank(request.getUserIP())) {
            param.put("userIp", request.getUserIP());
        }
        if (param.size() > 0) {
            userDTO.setExtInfo(param);
        }
        return userDTO;
    }

    @Override
    protected void registerExtensions(String userId, AbstractAuthRequest request) {
        WechatAuthRequest wechatAuthRequest = (WechatAuthRequest) request;
        WechatUserDTO dto = new WechatUserDTO();
        dto.setUserId(userId);
        String defaultAppid;
        if (WechatOpenIdTypeEnum.WECHAT_MP.getCode().equals(wechatAuthRequest.getOpenidType())) {
            dto.setOpenId(wechatAuthRequest.getOpenid());
            defaultAppid = appProps.getWechatMpAppid();
        } else if (WechatOpenIdTypeEnum.NATIVE_APP.getCode().equals(
                wechatAuthRequest.getOpenidType())) {
            dto.setAppOpenId(wechatAuthRequest.getOpenid());
            dto.setOpenId(wechatAuthRequest.getOpenid());
            defaultAppid = appProps.getWechatAppAppid();
        } else {
            throw new InvokeServiceException(CommonServiceErrorEnum.REQUEST_PARAMETER_ERROR);
        }
        dto.setOpenidType(wechatAuthRequest.getOpenidType());
        dto.setUnionid(wechatAuthRequest.getUnionid());
        dto.setSubscribe(String.valueOf(wechatAuthRequest.getSubscribe()));
        // 关注时间有，转成日期类型，用的是标准unix时间戳(秒)，转换时需要*1000
        if (wechatAuthRequest.getSubscribeTime() > 0) {
            dto.setSubscribeTime(new Date(wechatAuthRequest.getSubscribeTime() * 1000L));
        }

        // 向下兼容处理，如果appid为空，使用默认微信公众号标识
        if (StringUtil.isBlank(wechatAuthRequest.getAppid())) {
            dto.setAppid(defaultAppid);
        } else {
            dto.setAppid(wechatAuthRequest.getAppid());
        }

        List<WechatUserDTO> list = wechatUserRepository.queryByUnionid(
                wechatAuthRequest.getUnionid(), dto.getAppid());

        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(wxUser -> {
                if (!checkOtherBinding(wxUser, userId)) {
                    // 当前用户的微信信息更新，被其他用户绑定过，会由 checkOtherBinding 抛出异常，
                    // 无效信息会置成废弃标识
                    boolean b = wechatUserRepository.modify(dto);
                    if (!b) {
                        throw new InvokeServiceException(CommonServiceErrorEnum.REQUEST_PARAMETER_ERROR);
                    }
                }
            });
        } else {
            wechatUserRepository.create(dto);
        }
    }

    @Override
    protected void registerCheck(AbstractAuthRequest request) {
        WechatAuthRequest wechatAuthRequest = (WechatAuthRequest) request;
        if (!checkSmsCode(wechatAuthRequest.getLoginId(), wechatAuthRequest.getVcode(),
                wechatAuthRequest.getVcodeNamespace())) {
            throw new InvokeServiceException(Errors.VCode.VCODE_VALIDATION_FAILS);
        }
    }

    /**
     * 检查是否其他用户绑定过
     * @param wechatUser unionid 查询出的微信信息
     * @param userId 当期用户userId，查询结果与当前userId不一致时，说明微信已被绑定过
     * @return 微信信息是否被废弃
     */
    private boolean checkOtherBinding(WechatUserDTO wechatUser, String userId) {
        UserDTO userDTO = userRepository.queryByPK(wechatUser.getUserId());
        // XXX 对只预注册的处理，以前预注册只会落地微信，用户不会存，将这种微信信息置为无效，之后用户可以重新注册
        boolean disabled = false;
        if (userDTO == null) {
            boolean b = wechatUserRepository.updateDsiable(1, wechatUser.getUserId());
            if (!b) {
                throw new InvokeServiceException(CommonServiceErrorEnum.SYSTEM_ERROR);
            }
            disabled = true;
        }
        // 不是同一个用户，抛出异常
        if (!disabled && !StringUtil.equals(userId, wechatUser.getUserId())) {
            throw new InvokeServiceException(Errors.User.WECHAT_HAS_BINDING_USER);
        }
        return disabled;
    }
}
